#ifndef LOGGER_HPP
#define LOGGER_HPP

#include <iostream>
#include <fstream>
#include <chrono>
#include <ctime>
#include <string>
#include <sstream>
#include <iomanip>
#include <memory>
#include <filesystem>
#include <mutex>
#include <fcntl.h>
#include <unistd.h>
#include <sys/file.h>
#include <semaphore.h>

#define GET_LOCAL_TIME                                                                                              \
    []() {                                                                                                          \
        auto now = std::chrono::system_clock::now();                                                                \
        auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;             \
        std::time_t t = std::chrono::system_clock::to_time_t(now);                                                  \
        std::tm tm = *std::localtime(&t);                                                                           \
        std::ostringstream oss;                                                                                     \
        oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S.") << std::setw(3) << std::setfill('0') << ms.count() << ": "; \
        return oss.str();                                                                                           \
    }()
#define FILE_LINE  __FILE__ << "[" << __LINE__ << "] - "
#define LOG(level) Logger::getInstance() << " - [" << level << "] - " << FILE_LINE
// #define LOG_MSG(level, message) Logger::getInstance().log(level, FILE_LINE, message)
#define OUTPUT_ERRR LOG("ERRR")
#define OUPUT_INFO  LOG("INFO")

class Logger {
private:
    std::ofstream logFile;
    std::chrono::system_clock::time_point lastFileCreationTime;
    std::ostringstream buffer;
    std::mutex mutex_;
    sem_t* semaphore;

    Logger() {
        createNewLogFile();
        // 创建或打开一个命名信号量
        semaphore = sem_open("/logger_semaphore", O_CREAT, 0644, 1);
        if (semaphore == SEM_FAILED) {
            throw std::ios_base::failure("Failed to create/open semaphore");
        }
    }

    // 获取当前日志文件路径
    std::string getLogFilePath() {
        auto now = std::chrono::system_clock::now();
        auto t = std::chrono::system_clock::to_time_t(now);
        std::tm tm = *std::localtime(&t);

        std::ostringstream oss;
        // 创建以日期为目录名称的路径
        oss << "/home/pi/log/" << std::put_time(&tm, "%Y-%m-%d") << "/";
        // 确保每小时创建新日志文件
        oss << std::put_time(&tm, "%Y-%m-%d_%H") << "_logs.log";
        return oss.str();
    }
    std::string get_local_time() {
        auto now = std::chrono::system_clock::now();
        auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
        std::time_t t = std::chrono::system_clock::to_time_t(now);
        std::tm tm = *std::localtime(&t);
        std::ostringstream oss;
        oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S.") << std::setw(3) << std::setfill('0') << ms.count();
        return oss.str();
    }

    // 创建新的日志文件
    void createNewLogFile() {
        auto now = std::chrono::system_clock::now();
        auto now_time_t = std::chrono::system_clock::to_time_t(now);
        std::tm now_tm = *std::localtime(&now_time_t);

        // 判断是否是新的一天或间隔超过 2 小时
        if (logFile.is_open()) {
            logFile.close();
        }

        std::string filePath = getLogFilePath();
        std::filesystem::create_directories(std::filesystem::path(filePath).parent_path());
        logFile.open(filePath, std::ios::app);

        if (logFile.is_open()) {
            logFile << "[" << GET_LOCAL_TIME << "] 新日志文件创建成功\n";
            lastFileCreationTime = now;
        } else {
            std::cerr << "[" << GET_LOCAL_TIME << "] 无法创建日志文件: " << filePath << std::endl;
        }
    }

    // 检查是否需要创建新的日志文件
    void checkAndCreateNewLogFile() {
        auto now = std::chrono::system_clock::now();
        auto durationSinceLastFile = std::chrono::duration_cast<std::chrono::hours>(now - lastFileCreationTime).count();

        auto now_time_t = std::chrono::system_clock::to_time_t(now);
        std::tm now_tm = *std::localtime(&now_time_t);

        if (durationSinceLastFile >= 2 || (now_tm.tm_hour == 0 && now_tm.tm_min == 0)) {
            createNewLogFile();
        }
    }

public:
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

    static Logger& getInstance() {
        static Logger instance;
        return instance;
    }

    // 日志输出（支持各种数据类型）
    template <typename T>
    Logger& operator<<(const T& message) {
        std::lock_guard<std::mutex> lock(mutex_);
        buffer << message;  // 写入缓冲区
        return *this;
    }

    // 支持格式化操作符（如 std::dec、std::hex 等）
    Logger& operator<<(std::ios_base& (*manip)(std::ios_base&)) {
        std::lock_guard<std::mutex> lock(mutex_);
        buffer << manip;  // 写入缓冲区
        return *this;
    }

    // 支持流操作符（如 std::endl）
    Logger& operator<<(std::ostream& (*manip)(std::ostream&)) {
        std::lock_guard<std::mutex> lock(mutex_);
        buffer << manip;  // 写入缓冲区
        flush();          // 输出缓冲区内容
        return *this;
    }

    // 输出日志信息
    // Logger& log(const std::string& message) {
    //     checkAndCreateNewLogFile();
    //     std::cout << message << std::endl;
    //     if (logFile.is_open()) {
    //         logFile << message << std::endl;
    //     }
    //     return *this;
    // }

    // 输出缓冲区内容
    void flush() {
        std::string logMessage = buffer.str();
        buffer.str("");  // 清空缓冲区
        buffer.clear();

        // 加锁
        if (sem_wait(semaphore) == -1) {
            buffer << GET_LOCAL_TIME << "[Logger] Warning: Unable to acquire semaphore.";
            return;
        }

        logFile << GET_LOCAL_TIME << logMessage;    // 写入文件
        std::cout << GET_LOCAL_TIME << logMessage;  // 输出到控制台
        logFile.flush();

        // 解锁
        if (sem_post(semaphore) == -1) {
            buffer << GET_LOCAL_TIME << "[Logger] Warning: Unable to release semaphore.";
            return;
        }
    }

    // // 打印带文件名和行号的日志
    // void log(const std::string& level, const std::string& message, const std::string& file) {
    //     std::lock_guard<std::mutex> lock(mutex_);
    //     std::string logEntry = get_local_time() + level + message + file;
    //     logFile << logEntry << std::endl;
    //     std::cout << logEntry << std::endl;
    // }

    ~Logger() {
        if (logFile.is_open()) {
            logFile << "[" << GET_LOCAL_TIME << "] 日志文件关闭\n";
            logFile.close();
        }
    }
};

#endif  // LOGGER_HPP
